/*! \file UART_Protocol.c*/
/*
 * @Description: UART_MT3Y协议解析控制
 * @Version: 0.2
 * @Autor: 宣某
 * @Date: 2021-02-23 11:28:38
 * @FilePath: \宣某提交库\MT3Y_Protocol\UART_Protocol.c
 * @LastEditors: 宣某
 * @LastEditTime: 2021-05-06 16:19:56
 */
#include "Protocol.h"

#include "stm32f10x.h"

/*!< 拆分协议移入4Bit数据,x:接收目标地,y:4Bit数据*/
#define ISOLATE_ENQUEUE(x, y) \
    do                        \
    {                         \
        (x) <<= 4;            \
        (y) &= 0x0f;          \
        (x) |= (y);           \
    } while (0)
#define SEND_UART USART1
/*!< 串口发送1Byte数据*/
#define UART_SEND_BYTE(DATA)                                      \
    do                                                            \
    {                                                             \
        SEND_UART->DR = DATA;                                     \
        while (USART_GetFlagStatus(SEND_UART, USART_FLAG_TXE) == RESET) \
            ;                                                     \
    } while (0)

/// 超时检测的Struct
struct __TimeOut_Cheak
{
    unsigned char ENABLE;
    uint64_t Count;
    uint64_t OverFlow_Count;
} TimeOut_Cheak = {0, 0, 0};

/// 串口接收协议各部分的计数
struct __UART_Module_Count
{
    /// 接收长度段的字节计数
    unsigned char Len;
    /// 接收命令段的字节计数
    unsigned char Com;
    /// 接收数据段的字节计数
    unsigned short Data;
    /// 接收校验段的字节计数
    unsigned char LRC;
} UART_Module_Count = {0, 0, 0};

/// MT3Y模式枚举
typedef enum
{
    Isolate = 0, /*!< 拆分*/
    Combine      /*!< 合并*/
} __MT3Y_Mode;

/// 当前协议栈接受中的协议类型(HEAD时无效)
__MT3Y_Mode MT3Y_Mode = Isolate;

/*!< 串口接收协议各部分的函数*/
typedef void (*_Uart_Rec_Process_Func)(unsigned char);
/*!< 串口接收协议各部分的函数声明*/
static void Rx_Head(unsigned char _Data); // 接收协议头
static void Rx_Len(unsigned char _Data);  // 接收协议长度域
static void Rx_Com(unsigned char _Data);  // 接收协议命令域
static void Rx_Data(unsigned char _Data); // 接收协议数据域
static void Rx_LRC(unsigned char _Data);  // 接收LRC域
static void Rx_End(unsigned char _Data);  // 接收协议尾
/*!< 串口接收协议各部分的函数数组*/
_Uart_Rec_Process_Func Rec_Process_Func[6] =
    {
        Rx_Head,
        Rx_Len,
        Rx_Com,
        Rx_Data,
        Rx_LRC,
        Rx_End}; /*!< 协议栈接收流程*/

void Uart_Protocol_Init(unsigned short _TimeOut_Value);                                    /*!< 协议栈初始化*/
void Uart_ReSet(void);                                                                     /*!< 复位协议栈*/
void Uart_Receive_Handler(unsigned char _Data);                                            /*!< 协议栈接收一字节函数*/
void Uart_Transmit_Handler(unsigned short _Sta, unsigned char *_Buf, unsigned short _Len); /*!< 协议栈发送数据函数*/
void Uart_Protocol_sTick_Handler(void);                                                    /*!< 协议栈超时复位心跳*/

void Uart_Protocol_Set_Baud(unsigned int _Boud);/*!< 设置串口波特率接口 */
		
void Err_Save(__Uart_Rec_Process_Flag _Err);

/// 串口协议栈控制块
volatile __uart_protocol Uart_protocol =
 {
        .Flag = Head,                                 /*!< 协议栈流程标志*/
        .LRC = 0,                                     /*!< 协议实时LRC*/
        .Init = Uart_Protocol_Init,                   /*!< 初始化函数*/
        .Reset = Uart_ReSet,                          /*!< 复位函数*/
        .Receive_Handler = Uart_Receive_Handler,      /*!< 接收函数*/
        .Transmit_Handler = Uart_Transmit_Handler,    /*!< 发送函数*/
        .sTick_Handler = Uart_Protocol_sTick_Handler, /*!< 心跳提供函数*/
        .Succeed_CallBack = 0,                        /*!< 接收命令成功回调*/
		.Set_Baud = Uart_Protocol_Set_Baud,	/*!< 设置串口波特率接口 */
        //.ERR_CallBack = 0,   //接收数据失败回调
        .ERR_CallBack = Err_Save,                     /*!< 接收数据失败回调*/
        .Rx_Buffer = &Protocol_Rx_Buffer,             /*!< 接收数据缓冲区*/
        .Tx_Buffer = &Protocol_Tx_Buffer};            // 发送数据缓冲区

static void _UartX_Init(void)
{
	//GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE); 
    //USART1_TX   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);          

    //USART4_RX	 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;            
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //复用
    GPIO_Init(GPIOA, &GPIO_InitStructure);                

    //Usart4 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);                           //根据指定的参数初始化VIC寄存器

    //USART 初始化设置
    USART_InitStructure.USART_BaudRate = 115200;                                     //串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;                     //字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                          //一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;                             //无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 //收发模式

    USART_Init(USART1, &USART_InitStructure);      //初始化串口1
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启串口接受中断
    USART_Cmd(USART1, ENABLE);                     //使能串口1
}
/**
 * @description: 接收协议头流程函数
 * @param {unsigned char} _Data:本次接收的一字节数据
 * @return {*}
 * @author: 宣某
 */
static void Rx_Head(unsigned char _Data)
{
    /*!< 若收到的数据尾数据头0x02*/
    if (_Data == 0x02)
    {
        /*!< 各数据域接收字节变量复位*/
        UART_Module_Count.Len = 0;
        UART_Module_Count.Com = 0;
        UART_Module_Count.Data = 0;
        UART_Module_Count.LRC = 0;
		/// 复位LRC数据
		Uart_protocol.LRC = 0;
        /*!< 接收标志指向长度域*/
        Uart_protocol.Flag = Len;
    }
}

/**
 * @description: 接收协议长度域流程函数
 * @param {unsigned char} _Data:本次接收的一字节数据
 * @return {*}
 * @author: 宣某
 */
static void Rx_Len(uint8_t _Data)
{
    /*!< 长度域接收到的数据字节数++*/
    UART_Module_Count.Len++;
    /*!< 区分拆分与合并接口*/
    if(UART_Module_Count.Len == 1)
	{
		if(_Data >= 0x30)
			MT3Y_Mode = Isolate;
		else
			MT3Y_Mode = Combine;
	}
    /*!< 处理合并协议 ---------------------------*/ 
    /*!< 处理合并协议 ---------------------------*/
    if (MT3Y_Mode == Combine) 
    {
        /*!< 向长度域移入8Bit*/
        Uart_protocol.Rx_Buffer->Length <<= 8;
        Uart_protocol.Rx_Buffer->Length |= _Data;
        /*!< 合并协议长度域接收两字节后接收完成*/
        if (UART_Module_Count.Len == 2)
        {
            /*!< 接收标志指向命令域*/
            Uart_protocol.Flag = Com; 
            /*!< 看看协议缓冲能不能收的下这包数据*/
            if(Uart_protocol.Rx_Buffer->Length > DATA_SIZE)
                /*!< 若有错误回调,则调用错误回调*/
                if (Uart_protocol.ERR_CallBack != 0)
                    Uart_protocol.ERR_CallBack(Len);
        }  
    }
    /*!< 处理拆分协议-------------------------------*/
    /*!< 处理拆分协议-------------------------------*/
    else if (MT3Y_Mode == Isolate) 
    {
        /*!< 向长度域移入4Bit*/
        ISOLATE_ENQUEUE(Uart_protocol.Rx_Buffer->Length, _Data);
        /*!< 拆分协议长度域接收四字节后接收完成*/
        if (UART_Module_Count.Len == 4)
        {
            /*!< 接收标志指向命令域*/
            Uart_protocol.Flag = Com; 
            /*!< 看看协议缓冲能不能收的下这包数据*/
            if(Uart_protocol.Rx_Buffer->Length > DATA_SIZE)
                /*!< 若有错误回调,则调用错误回调*/
                if (Uart_protocol.ERR_CallBack != 0)
                    Uart_protocol.ERR_CallBack(Len);
        }
    }
    else
    {
       //正常不可能出现在这里
       do{}while (0);       
    }    
}
/**
 * @description: 接收协议命令域流程函数
 * @param {unsigned char} _Data:本次接收的一字节数据
 * @return {*}
 * @author: 宣某
 */
static void Rx_Com(unsigned char _Data)
{
    //命令域接收到的数据字节数++
    UART_Module_Count.Com++;
    if (MT3Y_Mode == Combine) //合并协议
    {
        //向命令域移入8Bit
        Uart_protocol.Rx_Buffer->Cmd <<= 8;
        Uart_protocol.Rx_Buffer->Cmd |= _Data;
		//计算LRC
		Uart_protocol.LRC ^= _Data;
        //合并协议命令域接收两字节后接收完成
        if (UART_Module_Count.Com == 2) //无数据域则指向LRC,有数据指向数据域
            (Uart_protocol.Rx_Buffer->Length == 2) ? (Uart_protocol.Flag = LRC) : (Uart_protocol.Flag = Data);
    }
    else if (MT3Y_Mode == Isolate) //拆分协议
    {
        //向命令域移入4Bit
        ISOLATE_ENQUEUE(Uart_protocol.Rx_Buffer->Cmd, _Data);
        //拆分协议命令域接收四字节后接收完成
        if (UART_Module_Count.Com == 4)
        {
            //开始计算LRC
            Uart_protocol.LRC = (Uart_protocol.Rx_Buffer->Cmd >> 8) & 0xFF;
            Uart_protocol.LRC ^= (Uart_protocol.Rx_Buffer->Cmd & 0xFF);
            //无数据域则指向LRC,有数据指向数据域
            (Uart_protocol.Rx_Buffer->Length == 2) ? (Uart_protocol.Flag = LRC) : (Uart_protocol.Flag = Data);
        }
    }
    else
    {
        //正常不可能出现在这里
        do
        {
        } while (0);
    }
}
/**
 * @description: 接收协议数据域流程函数
 * @param {unsigned char} _Data:本次接收的一字节数据
 * @return {*}
 * @author: 宣某
 */
static void Rx_Data(unsigned char _Data)
{
    static unsigned short Isolate_Count = 0; //拆分接收计数
    //数据域接收数据量++
    UART_Module_Count.Data++;
    if (MT3Y_Mode == Combine) //合并协议
    {
        //计算本字节LRC
        Uart_protocol.LRC ^= _Data;
        //向数据域写入一字节数据
        Uart_protocol.Rx_Buffer->Data[UART_Module_Count.Data - 1] = _Data;
        //数据域数据接收完成,标志指向LRC
        if (UART_Module_Count.Data == (Uart_protocol.Rx_Buffer->Length - 2))
            Uart_protocol.Flag = LRC;
    }
    else if (MT3Y_Mode == Isolate) //拆分协议
    {
        if (UART_Module_Count.Data % 2) //若数据为高4Bit
        {
            //数据域首次接收数据,拆分接收计数清零
            if (UART_Module_Count.Data == 1)
                Isolate_Count = 0;
            //数据域移入4Bit
            ISOLATE_ENQUEUE(Uart_protocol.Rx_Buffer->Data[Isolate_Count], _Data);
        }
        else //若数据为低4Bit
        {
            //数据域移入4Bit
            ISOLATE_ENQUEUE(Uart_protocol.Rx_Buffer->Data[Isolate_Count], _Data);
            //计算本字节LRC
            Uart_protocol.LRC ^= Uart_protocol.Rx_Buffer->Data[Isolate_Count++];
            //数据域数据接收完成,标志指向LRC
            if (Isolate_Count == (Uart_protocol.Rx_Buffer->Length - 2))
                Uart_protocol.Flag = LRC;
        }
    }
}
/**
 * @description: 接收协议LRC域流程函数
 * @param {unsigned char} _Data:本次接收的一字节数据
 * @return {*}
 * @author: 宣某
 */
static void Rx_LRC(uint8_t _Data)
{
    static uint8_t Isolate_LRC = 0; //拆分协议接收到的LRC
    //接收到的LRC域数据++
    UART_Module_Count.LRC++;
    if (MT3Y_Mode == Combine) //合并协议
    {
        //若接收到的LRC与计算的相同,标志指向数据尾
        if ((Uart_protocol.LRC ^ _Data) == 0)
        {
            Uart_protocol.Flag = End;
        }
        //若接收到的LRC与计算的不同,标志指向数据头
        else
        {
            //若有错误回调,则调用错误回调
            if (Uart_protocol.ERR_CallBack != 0)
                Uart_protocol.ERR_CallBack(LRC);
            //标志指向数据头
            Uart_protocol.Flag = Head;
        }
    }
    else if (MT3Y_Mode == Isolate) //拆分协议
    {
        //向LRC域移入4Bit数据
        ISOLATE_ENQUEUE(Isolate_LRC, _Data);
        //若LRC接收完成
        if (UART_Module_Count.LRC == 2)
        {
            //若接收到的LRC与计算的相同,标志指向数据尾
            if ((Isolate_LRC ^ Uart_protocol.LRC) == 0)
            {
                Uart_protocol.Flag = End;
            }
            //若接收到的LRC与计算的不同,标志指向数据头
            else
            {
                //若有错误回调,则调用错误回调
                if (Uart_protocol.ERR_CallBack != 0)
                    Uart_protocol.ERR_CallBack(LRC);
                //标志指向数据头
                Uart_protocol.Flag = Head;
            }
        }
    }
}
/**
 * @description: 接收协议数据尾流程函数
 * @param {unsigned char} _Data:本次接收的一字节数据
 * @return {*}
 * @author: 宣某
 */
static void Rx_End(unsigned char _Data)
{
    //若收到的数据为数据尾0x03
    if (_Data == 0x03)
    {
        //接收标志转向接收成功
        Uart_protocol.Flag = Valid;
        //若有接收成功回调则调用成功回调
        if (Uart_protocol.Succeed_CallBack != 0)
            Uart_protocol.Succeed_CallBack();
    }
    //若收到的数据不为数据尾0x03
    else
    {
        //接收标志转向数据头
        Uart_protocol.Flag = Head;
        //若有错误回调,则调用错误回调
        if (Uart_protocol.ERR_CallBack != 0)
            Uart_protocol.ERR_CallBack(End);
    }
}
/**
 * @description: Uart协议栈心跳函数
 * @param {*}
 * @return {*}
 * @author: 宣某
 */
void Uart_Protocol_sTick_Handler(void)
{
    //心跳计数++
    TimeOut_Cheak.Count++;
    //若超时检测启动
    if (TimeOut_Cheak.ENABLE)
    { 
        //若检测到超时
        if (TimeOut_Cheak.OverFlow_Count == TimeOut_Cheak.Count)
        {  
            //若有错误回调,则调用错误回调          
            if (Uart_protocol.ERR_CallBack != 0)
                Uart_protocol.ERR_CallBack(TIMEOUT);
            //复位协议栈
            Uart_protocol.Reset();
        }
    }
}
/*!< 设置串口波特率接口 */
void Uart_Protocol_Set_Baud(unsigned int _Boud)
{
	USART_InitTypeDef USART_InitStructure;
	//USART 初始化设置
    USART_InitStructure.USART_BaudRate = _Boud;                                     //串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;                     //字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                          //一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;                             //无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 //收发模式

    USART_Init(UART4, &USART_InitStructure);      //初始化串口4
}

/**
 * @description: Uart协议栈初始化函数
 * @param {unsignedshort} _TimeOut_Value:接收字符间间隔超时所需要的心跳个数,心跳个数太小时容易出现异常的timeout
 * @return {*}
 * @author: 宣某
 */
void Uart_Protocol_Init(unsigned short _TimeOut_Value)
{
    //硬件初始化
    _UartX_Init();
    //设置超时所需要的心跳个数
    Uart_protocol.TimeOut_Value = _TimeOut_Value;
    //复位协议栈
    Uart_ReSet();
}
/**
 * @description: 协议栈复位函数
 * @param {*}
 * @return {*}
 * @author: 宣某
 */
void Uart_ReSet(void)
{
    //标志指向数据头
    Uart_protocol.Flag = Head;
    //协议栈各阶段接收计数清零
    UART_Module_Count.Len = 0;
    UART_Module_Count.Com = 0;
    UART_Module_Count.Data = 0;
    UART_Module_Count.LRC = 0;
}
/**
 * @description: 协议栈接收单字节函数
 * @param {unsignedchar} _Data:本次接收的1字节数据
 * @return {*}
 * @author: 宣某
 */
void Uart_Receive_Handler(unsigned char _Data)
{
    //若协议栈处于未接收完成状态
    if (Uart_protocol.Flag < Valid)
    {
        //关闭超时检测
        TimeOut_Cheak.ENABLE = 0;
        //根据协议栈接收标志进入对应数据域的接收函数
        Rec_Process_Func[Uart_protocol.Flag](_Data);
        switch (Uart_protocol.Flag)
        {
        //数据头与接收完成阶段不更新超时心跳计数
        case Valid:
        case Head:
            break;
        default:
        //更新超时心跳计数,启动超时检测
            TimeOut_Cheak.OverFlow_Count = TimeOut_Cheak.Count + Uart_protocol.TimeOut_Value;
            TimeOut_Cheak.ENABLE = 1;
            break;
        }
    }
    //若协议栈处于完成状态时仍然接收到数据
    //若有错误回调,则调用错误回调       
    else if (Uart_protocol.ERR_CallBack != 0)
        Uart_protocol.ERR_CallBack(Valid);
}


/**
 * @description: Uart协议栈发送函数
 * @param {unsignedshort} _Sta:返回的状态码
 * @param {unsignedchar} *_Buf:返回的数据的缓冲区
 * @param {unsignedshort} _Len:返回数据的长度
 * @return {*}
 * @author: 宣某
 */
void Uart_Transmit_Handler(unsigned short _Sta, unsigned char *_Buf, unsigned short _Len)
{
    unsigned char LRC = 0;//LRC
    //发送包头
    UART_SEND_BYTE(0x02);
    if (MT3Y_Mode == Combine)//合并模式
    {
        //发送包长
        _Len += 2;
        UART_SEND_BYTE(_Len >> 8);
        UART_SEND_BYTE(_Len & 0xFF);
        _Len -= 2;
        //发送状态码
        UART_SEND_BYTE(_Sta >> 8);
        UART_SEND_BYTE(_Sta & 0xFF);
        //开始计算LRC
        LRC ^= (_Sta >> 8);
        LRC ^= (_Sta & 0xFF);
        //循环发送数据域,并计算LRC
        while (_Len--)
        {
            UART_SEND_BYTE(*_Buf);
            LRC ^= *(_Buf++);
        }
        //发送LRC
        UART_SEND_BYTE(LRC);
    }
    else if (MT3Y_Mode == Isolate)//拆分模式,发送数据将1Byte拆未上下4Bit,再分别与上0x30再发送
    {
        //发送包长
        _Len += 2;
        UART_SEND_BYTE(((_Len >> 12) & 0x0F) | 0x30);
        UART_SEND_BYTE(((_Len >> 8) & 0x0F) | 0x30);
        UART_SEND_BYTE(((_Len >> 4) & 0x0F) | 0x30);
        UART_SEND_BYTE((_Len & 0x0F) | 0x30);
        _Len -= 2;
        //发送状态码
        UART_SEND_BYTE(((_Sta >> 12) & 0x0F) | 0x30);
        UART_SEND_BYTE(((_Sta >> 8) & 0x0F) | 0x30);
        UART_SEND_BYTE(((_Sta >> 4) & 0x0F) | 0x30);
        UART_SEND_BYTE((_Sta & 0x0F) | 0x30);
        //开始计算LRC
        LRC ^= (_Sta >> 8);
        LRC ^= (_Sta & 0xFF);
        //循环发送数据域,并计算LRC
        while (_Len--)
        {
            UART_SEND_BYTE((((*_Buf) >> 4) & 0x0F) | 0x30);
            UART_SEND_BYTE(((*_Buf) & 0x0F) | 0x30);
            LRC ^= *(_Buf++);
        }
        //发送LRC
        UART_SEND_BYTE(((LRC >> 4) & 0x0F) | 0x30);
        UART_SEND_BYTE((LRC & 0x0F) | 0x30);
        // UART_SEND_BYTE(LRC);
    }
    //发送协议尾
    UART_SEND_BYTE(0x03);
    //协议栈状态标志指向数据头,开始新一轮接收
    Uart_protocol.Flag = Head;
}


/**
 * @description: 协议栈产生错误时的回调,可自定义
 * @param {unsigned char} _Err
 * @return {*}
 * @author: 宣某
 */
 __Uart_Rec_Process_Flag ERR_Save_Array[50] = {Head};
void Err_Save(__Uart_Rec_Process_Flag _Err)
{
     static unsigned char Err_Count = 0;
     ERR_Save_Array[Err_Count++] = _Err;
     if (Err_Count > sizeof(ERR_Save_Array))
         Err_Count = 0;
}
